package codeine.servlets;

import java.io.File;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import codeine.NodesManagerServer;
import codeine.configuration.ConfigurationManager;
import codeine.configuration.Links;
import codeine.configuration.PathHelper;
import codeine.jsons.command.CommandJson;
import codeine.jsons.labels.LabelJsonProvider;
import codeine.jsons.nodes.NodeJson;
import codeine.jsons.project.ProjectJson;
import codeine.jsons.project_status.PeersProjectsStatus;
import codeine.jsons.project_status.ProjectStatus;
import codeine.jsons.project_status.ProjectStatusList;
import codeine.model.Constants;
import codeine.servlet.AbstractServlet;
import codeine.servlet.HtmlHeaderWriter;
import codeine.servlet.PermissionsManager;
import codeine.utils.HttpUtils;
import codeine.utils.InetUtils;
import codeine.utils.StringUtils;
import codeine.version.ViewNodesFilter;

import com.google.inject.Inject;

public class DashboardServlet extends AbstractServlet {
	private static final Logger log = Logger.getLogger(DashboardServlet.class);
	private static final long serialVersionUID = 1L;
	@Inject
	private ConfigurationManager configurationManager;
	@Inject
	private PeersProjectsStatus peersProjectsStatus;
	@Inject
	private Links links;
	@Inject
	private NodesManagerServer nodesManager;
	@Inject
	private HtmlHeaderWriter htmlHeaderWriter;
	@Inject
	private PermissionsManager permissionsManager;
	@Inject
	private LabelJsonProvider versionLabelJsonProvider;
	@Inject
	private PathHelper pathHelper;

	@Override
	protected void myGet(HttpServletRequest request, HttpServletResponse response) {
		log.debug("dashboard request");
		String projectName = request.getParameter("project");
		String paramVersion;
		int paramMax;
		paramVersion = request.getParameter("version");
		String countString = request.getParameter("count");
		String regexp = request.getParameter("regexp");
		paramMax = Integer.MAX_VALUE;
		if (null != countString) {
			paramMax = Integer.valueOf(countString);
		}
		boolean alerts = "true".equals(request.getParameter("alerts"));
		boolean readOnly = !permissionsManager.isModifiable(projectName, request);

		ViewNodesFilter versionFilter = new ViewNodesFilter(paramVersion, paramMax, regexp);
		PrintWriter writer = getWriter(response);
		String view = alerts ? "alerts" : "dashboard";
		htmlHeaderWriter.writeHeader(request, response, projectName, projectName + " / " + view);
		ProjectJson project = configurationManager.getProjectForName(projectName);
		boolean hasSwitchVersionDefined = false;
		boolean hasSwitchVersionScript = hasSwitchVersionScript(project.name());
		if (!readOnly) {
			writer.println("<alert><div class=\"alertbar\">");
			writer.println("<button class=\"command\" onClick=\"selectAll()\">Select all</button>");
			writer.println("<input class=\"version\" type=\"text\" title='enter parameter for command' id=\"commandAllArgs\" />");
			for (CommandJson command : project.commands()) {
				if (!command.one_at_a_time()) {
					writer.println("<button class=\"command\" onClick=\"commandCheckedItems('" + projectName + "', '"
							+ command.name() + "')\">" + command.title() + " (selected nodes)</button>");
					if (command.name().equals("switch-version")) {
						hasSwitchVersionDefined = true;
					}
				}
			}
			if (!hasSwitchVersionDefined && hasSwitchVersionScript) {
				writer.println("<button class=\"command\" onClick=\"switchVersionToCheckedItems('" + projectName
						+ "')\">Switch version to selected nodes</button>");
			}
			writer.println("</div></alert>");
		}
		for (Entry<String, ProjectStatusList> e1 : peersProjectsStatus.peer_to_projects.entrySet()) {
			String peerName = e1.getKey();
			String peerNameNoPort = InetUtils.nameWithoutPort(peerName);
			ProjectStatus projectStatus = e1.getValue().project_name_to_status.get(projectName);
			if (null == projectStatus) {
				log.info("no status for peer " + peerName);
				continue;
			}
			List<NodeJson> nodes = nodesManager.getNodes(project, peerNameNoPort);
			for (NodeJson nodeJson : nodes) {

				Map<String, String> nodeMap = projectStatus.monitor_to_status().get(nodeJson.name());
				if (null == nodeMap) {
					log.info("no status for node " + nodeJson.name());
					continue;
				}
				String version = nodeMap.get("version");
				if (versionFilter.filter(version, nodeJson.alias())) {
					continue;
				}
				// Node internalNode = node.peer.internalNode();
				// CollectorOnNodeState keepaliveResult =
				// dataStore.getResult(internalNode, new KeepaliveCollector());
				boolean fail = nodeMap.values().contains("false");
				if (!fail && alerts) {
					continue;
				}
				// start building monitored instance line:
				String line = "            <alert><div class=\"alertbar\"><ul>";
				String className = fail ? "b" : "g";
				String nodeNameToDisplay = nodeJson.alias();
				if (!readOnly) {
					line += "<li><input class=\"checkbox\" type=\"checkbox\" id=\"checkbox_" + peerName + "\"/></li>";
				}
				line += "<li><a class=\"name" + className + "\" href=\"" + links.getLogLink(peerName) + "\">"
						+ nodeNameToDisplay + "</a></li>";
				// build result buttons for each collector:
				for (Entry<String, String> e2 : nodeMap.entrySet()) {
					if (e2.getKey().equals("version")) {
						continue;
					}
					log.debug("result for " + peerName + " is: " + e2);
					// if (node.disabled())
					// {
					// line +=
					// "<li><a class=\"na\" title=\"node is disabled\" href=\"na\">?</a></li>";
					// }
					// else if (!keepaliveResult.state())
					// {
					// line +=
					// "<li><a class=\"na\" title=\"keepalive is dead\" href=\""
					// + getLink(collector, node) + "\">?</a></li>";
					// }
					// else if (null == result)
					// {
					// line += "<li><a class=\"na\" title=\"" + collector.name +
					// "\" href=\"" + getLink(collector, node) +
					// "\">?</a></li>";
					// }
					// else
					// {
					// change css class depending on result:
					boolean state = e2.getValue().equals("true");
					String goodbad = state ? "good" : "bad";
					String link = HttpUtils.encode(getLink(peerName, projectName, e2.getKey(), nodeJson.name()));
					String p = "?project=" + HttpUtils.encode(projectName) + "&link=" + link;
					line += "<li><a class=\"" + goodbad + "\" title=\"" + e2.getKey() + "\" href=\""
							+ Constants.MONITOR_OUTPUT_CONTEXT + p + "\">?</a></li>";//
					// }
				}
				String versionClass = "version" + className;
				if (!StringUtils.isEmpty(version)) {
					String versionLabel = versionLabelJsonProvider.labelForVersion(version, projectName);
					String versionInPeerLink = "nonei";
					line += "<li><a class=\"" + versionClass + "\" href=\"" + versionInPeerLink + "\">" + versionLabel
							+ "</a></li>";
				}
				if (!readOnly) {
					line += "<li>" + "<input class=\"version\" type=\"text\" title='enter parameter for command' id=\""
							+ peerName + "_commandParams\" />" + "</li>";
					for (CommandJson command : project.commands()) {
						String link = links.getPeerCommandLink(peerName, projectName, command.name(), "");
						line += "<li>" + "<button class=\"command\" onClick=\"commandNode('" + peerName + "','"
								+ command.title() + "','" + link + "','" + projectName + "')\">" + command.title()
								+ "</button>" + "</li>";
						if (command.name().equals("switch-version")) {
							hasSwitchVersionDefined = true;
						}
					}
					if (!hasSwitchVersionDefined && hasSwitchVersionScript)// gc.isSwitchVersionEnabled())
					{
						String link = links.getPeerCommandLink(peerName, projectName, "switch-version", "");
						line += "<li>" + "<button class=\"command\" onClick=\"switchVersion('" + peerName + "','"
								+ link + "','" + projectName + "')\">Switch-Version</button>" + "</li>";
					}
				}
				line += "</ul><br style=\"clear:left\"/></div></alert>";
				writer.println(line);
			}
		}
		htmlHeaderWriter.writeFooter(response);
	}

	private boolean hasSwitchVersionScript(String project) {
		for (File file : pathHelper.getPlugins(project)) {
			if (file.getName().equals("switch-version")) {
				return true;
			}
		}
		for (File file : pathHelper.getMonitors(project)) {
			if (file.getName().equals("switch-version")) {
				return true;
			}
		}
		return false;
	}

	private String getLink(String hostport, String project, String monitor, String nodeName) {
		return links.getPeerMonitorResultLink(hostport, project, monitor, nodeName);
	}

}
